/**
 * 
 */
package tests;

import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import network.Address;

import org.junit.Test;

import coreAlgorithm.ID;
import coreAlgorithm.NodeTriple;

/**
 * @author peter
 * 
 */
public class NodeTripleTest {

	/**
	 * Test method for {@link coreAlgorithm.NodeTriple#clone()}.
	 */
	@Test
	public final void testClone() {
		ID nodeID = new ID("1101");
		NodeTriple nt = new NodeTriple(new Address("xx"), nodeID, 3);
		NodeTriple ntClone = nt.clone();
		assertNotSame(nt, ntClone);
		assertEquals(nt.getAddress(), ntClone.getAddress());
		assertEquals(nt.getNodeID(), ntClone.getNodeID());
		assertEquals(nt.getLastSeen(), ntClone.getLastSeen());
	}

	@Test
	public final void testEquals() {
		NodeTriple nt1 = new NodeTriple(new Address("add1"), new ID(3), 0);
		NodeTriple nt2 = new NodeTriple(new Address("3"), new ID(3), 4);
		NodeTriple nt3 = new NodeTriple(new Address("4"), new ID(5), 0);
		assertEquals(nt1, nt2);
		assertNotSame(nt1, nt3);
		assertNotSame(nt2, nt3);
		assertFalse(nt3.equals("bla"));
	}
	
	@Test
	public final void testHashCode() {

		NodeTriple nt1 = new NodeTriple(new Address("add1"), new ID(3), 0);
		NodeTriple nt2 = new NodeTriple(new Address("3"), new ID(3), 4);
		NodeTriple nt3 = new NodeTriple(new Address("4"), new ID(5), 0);
		
		Set<NodeTriple> set = new HashSet<NodeTriple>();
		assertTrue(set.add(nt1));
		assertTrue(set.add(nt3));
		assertFalse(set.add(nt2));
		assertEquals(2, set.size());
		assertTrue(set.remove(nt3));
		assertEquals(nt1.getAddress().getValue(), set.iterator().next().getAddress().getValue());
	}

	@Test
	public void testNearestComparator() throws Exception {
		int chosenValue = 2;
		Comparator<NodeTriple> comp = NodeTriple.NEAREST_TO_GIVEN_ID_COMPARATOR(new ID(chosenValue));

		ID sameID = new ID(325);
		assertEquals(0, comp.compare(new NodeTriple(new Address(""), new ID(sameID.integerValue()), 0), new NodeTriple(new Address(""), sameID, 0)));

		assertEquals(+1, comp.compare(new NodeTriple(new Address(""), new ID(1), 0), new NodeTriple(new Address(""), new ID(3), 0)));
		assertEquals(-1, comp.compare(new NodeTriple(new Address(""), new ID(chosenValue), 0), new NodeTriple(new Address(""), sameID, 0)));

		Random rand = new Random(System.currentTimeMillis());

		for (int i = 0; i < 1000; i++) {
			int first = Math.abs(rand.nextInt());
			int second = Math.abs(rand.nextInt());
			// System.out.println("First: " + first + " Second: " + second);
			int compResult = comp.compare(new NodeTriple(new Address(""), new ID(first), 0), new NodeTriple(new Address(""), new ID(second), 0));
			if (first == second)
				assertEquals(0, compResult);
			if (Math.abs(chosenValue - first) < Math.abs(chosenValue - second)) {
				assertEquals(-1, compResult);
			} else {
				assertEquals(+1, compResult);
			}
		}

		// Sort a list
		List<NodeTriple> listToSort = new ArrayList<NodeTriple>();
		listToSort.add(new NodeTriple(new Address(""), new ID(7), 0)); // 111
		listToSort.add(new NodeTriple(new Address(""), new ID(3), 0)); // 011
		listToSort.add(new NodeTriple(new Address(""), new ID(5), 0)); // 101
		Collections.sort(listToSort, NodeTriple.NEAREST_TO_GIVEN_ID_COMPARATOR(new ID(4))); // 100
		int[] expected = new int[] { 5, 7, 3 };
		for (int i = 0; i < expected.length; i++) {
			assertEquals(expected[i], listToSort.get(i).getNodeID().integerValue());
		}
		;
	}
}
